package javanetworking;

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Admin
 */
import java.security.*;
import java.io.*;
import java.util.List;
import java.nio.*;
import java.util.ArrayList;

public class GetMD5 {

    /**
     *
     * @param bytes MD5 bytes to String
     * @return
     */
    public String getHex(byte[] bytes) {
        StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append(Integer.toHexString((int) (b & 0xff)));
        }
        return result.toString();
    }

    /**
     *
     * @param fi ten file de hash MD5
     * @return mang gia tri md5 kieu byte
     */
    public byte[] getMD5(File fi) {
        try {
            if (fi.exists() == false) {
                return null;
            }
            byte[] buffer = new byte[(int) fi.length()];
            InputStream is = new FileInputStream(fi);
            is.read(buffer);
            is.close();
            MessageDigest md = MessageDigest.getInstance("MD5");
            md.update(buffer);
            byte[] md5 = md.digest();
            return md5;

        } catch (FileNotFoundException e) {
            System.out.println(e.getMessage());
        } catch (IOException e) {
            System.out.println(e.getMessage());
        } catch (NoSuchAlgorithmException e) {
            System.out.println(e.getMessage());
        }
        return null;
    }

    /**
     *
     * @param fi ten file
     * @param file_chunk kich thuoc 1 chunk
     * @throws FileNotFoundException
     * @throws IOException
     */
    public int splitFile_raw(File fi, int file_chunk) throws FileNotFoundException, IOException {
        long file_length = fi.length(); // do dai cua file
        FileInputStream fis = new FileInputStream(fi); // chuyen file thanh byte[]
        byte[] bytes = new byte[(int) file_chunk]; //tao byte[] de luu noi dung file
        long chunk_number = fi.length() / 524288; // so chunk cua file
        //System.out.println(chunk_number);
        for (int i = 0; i < chunk_number; i++) {
            int tmp = fis.read(bytes);
            System.out.println(tmp);
            File fi2 = new File(fi.getName() + ".chunk" + (i + 1));
            FileOutputStream fos = new FileOutputStream(fi2);
            fos.write(bytes, 0, tmp);
            fos.close();
        }
        fis.close();
        return (int) chunk_number;
    }

    public int splitFile(File fi, int file_chunk) throws FileNotFoundException, IOException {
        String newName;
        FileOutputStream chunk;
        int file_length = (int) fi.length(); // do dai cua file
        int nChunk = 0, read = 0, readLength = file_chunk;
        byte[] byteChunk;
        File dir=new File("chunks/"+fi.getName());
        dir.mkdirs();
        FileInputStream fis = new FileInputStream(fi);
        FileOutputStream writer=new FileOutputStream(new File("chunks/"+fi.getName()+"/"+fi.getName()+".chunk"));
        
        while (file_length > 0) {
            if (file_length <= file_chunk) {
                readLength = file_length;
            }
            byteChunk = new byte[readLength];
            read = fis.read(byteChunk, 0, readLength);
            file_length -= read;
            // assert (read == byteChunk.length);
            nChunk++;
            newName ="chunks/" +fi.getName()+"/"+fi.getName() + ".chunk" + Integer.toString(nChunk - 1);
            File newFile=new File(newName);
            chunk = new FileOutputStream(newFile);
            chunk.write(byteChunk);
            chunk.flush();
            chunk.close();
            GetMD5 ob=new GetMD5();
            String md5=ob.getHex(ob.getMD5(newFile));
            String line=newName+" "+md5+"\n";
            writer.write(line.getBytes());
            byteChunk = null;
            chunk = null;
            
        }
        writer.close();
        fis.close();
        fis = null;
        return (int) nChunk;
    }

    /**
     *
     * @param bFile file in bytes
     * @param filename new file name
     * @param ext new extend of file
     * @return
     * @throws FileNotFoundException
     * @throws IOException
     */
    public File convertBytesToFile(byte[] bFile, String filename, String ext) throws FileNotFoundException, IOException {
        filename = filename + "." + ext;
        File fi = new File(filename);
        FileOutputStream fos = new FileOutputStream(fi);
        fos.write(bFile);
        fos.close();
        return fi;
    }

    public File joinFiles(File fistChunk, int nFile) throws FileNotFoundException, IOException {
        List<byte[]> block = new ArrayList<>();
        /**
         * chuyen moi part thanh 1 mang byte add mang byte vao list block
         */
        for (int i = 0; i < nFile; i++) {
            File fi = new File("chunks/"+fistChunk.getName()+"/"+fistChunk.getName() + ".chunk" + (i));
            FileInputStream fis = new FileInputStream(fi);
            byte[] b = new byte[(int) fi.length()];
            fis.read(b);
            block.add(b);
            fis.close();
        }
        // implements an output stream in which the data is written into a byte array.
        ByteArrayOutputStream os = new ByteArrayOutputStream();
        for (byte[] b : block) {
            os.write(b, 0, b.length); // noi cac byte[] lai voi nhau bang os
        }
        byte[] fByte = os.toByteArray(); // tap mot byte[] chua tat cac cac byte[] trong block
        os.close();
        File newFile = new File("download/"+fistChunk.getName());// tao file moi
        FileOutputStream fos = new FileOutputStream(newFile);//ghi data cua stream ra file newFile
        fos.write(fByte);
        fos.close();
        return newFile;

    }

    public static void main(String[] args) throws InterruptedException, FileNotFoundException, IOException {
        //File fi = new File("nitro_pro8_Key[NP8D772561161D133E8].exe");//doc file
        GetMD5 ob = new GetMD5();
        File oFile = new File("Dinotasia_ Rivals (Extended) - YouTube.FLV");
        ob.joinFiles(oFile, 404);
        //System.out.println(ob.getHex(ob.getMD5(oFile))); // check MD5
        //int nFile = ob.splitFile(oFile, 524288); // so chunk
        //File newFile = ob.joinFiles(oFile, nFile);
        //System.out.println(ob.getHex(ob.getMD5(newFile))); // recheck MD5
       




    }
}